<?php

namespace App\Kuafu\Pay\Channel\MybankCashier;

use App\Kuafu\Mybank\Model\MybankOrderRecordModel;
use App\Kuafu\Mybank\Service\MybankCashierOrderService;
use App\Kuafu\Pay\BasePay;
use App\Kuafu\Pay\Enum\BasePayEnum;
use App\Kuafu\Pay\Enum\MyBankCashierPayEnum;
use App\Kuafu\Pay\Enum\PayCodeEnum;
use App\Kuafu\Pay\Exceptions\PayException;
use App\Kuafu\Pay\Jobs\PayPolling;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Model\RefundStreamModel;
use App\Kuafu\Pay\Service\ShopPayService;
use Illuminate\Support\Facades\Log;

class MybankCashierPay extends BasePay
{
    protected function initConfig(int $shopId, int $sysType)
    {
        // TODO: Implement initConfig() method.
    }

    public function faceToFacePay(string $subject, int $amount, string $authCode)
    {
        // TODO: Implement faceToFacePay() method.
    }

    public function closePay(string $outTradeNo): array
    {
        $payStream = PayStreamModel::suffix(null)->where('payNo', $outTradeNo)->first();
        if (!$payStream) {
            throw new PayException(PayCodeEnum::ERR_PAY_DATA_NOT_EXIST);
        }

        $result = (new MybankCashierOrderService)->closeOrder($outTradeNo, $payStream->thirdPayNo);

        $formatRes = $this->commonReturn($result);

        // kf订单号
        $formatRes['data']['outTradeNo'] = $outTradeNo;
        return $formatRes;
    }

    public function refund(string $outTradeNo, int $refundAmount): array
    {
        $payStream = PayStreamModel::suffix(null)->where('payNo', $outTradeNo)->first();
        if (!$payStream) {
            throw new PayException(PayCodeEnum::ERR_PAY_DATA_NOT_EXIST);
        }
        $model = new MybankCashierOrderService();

        $subject = PayStreamModel::SYS_TYPE_TEXT[$this->sysType] ?? '退款 - ';
        $subject .= "{$refundAmount}分";

        $result = $model->refundOrder($outTradeNo, $payStream->thirdPayNo, $refundAmount, $subject);

        $formatRes         = $this->commonReturn($result);
        $formatRes['data'] = [
            'thirdRefundNo' => $result['data']['refundOrderNo'] ?? '',
            'refundStatus'  => $this->convertRefundStatus(MyBankCashierPayEnum::REFUND_STATUS_APPLY),
        ];

        return $formatRes;
    }

    public function query(string $outTradeNo): array
    {
        $payStream = PayStreamModel::suffix(null)->where('payNo', $outTradeNo)->first();
        if (!$payStream) {
            throw new PayException(PayCodeEnum::ERR_PAY_DATA_NOT_EXIST);
        }

        $result = (new MybankCashierOrderService)->getOrderInfo($outTradeNo, $payStream->thirdPayNo, $payStream->shopId,
            $payStream->subject);

        $formatRes = $this->commonReturn($result);

        // 转换支付状态
        $formatRes['data'] = [
            'commonTradeStatus' => $this->convertTradeStatus($result['data']['status'] ?? 0),
            'totalPrice'        => (int)$payStream->payPrice,
            'payNo'             => $outTradeNo,
            'thirdPayNo'        => $payStream->thirdPayNo,
            'paySuccessTime'    => $result['data']['finishDateTime'] ?? 0,
        ];
        return $formatRes;
    }

    public function refundQuery(string $outTradeNo, string $outRequestNo): array
    {
        $payStream = PayStreamModel::suffix(null)->where('payNo', $outTradeNo)->first();
        if (!$payStream) {
            throw new PayException(PayCodeEnum::ERR_PAY_DATA_NOT_EXIST);
        }

        $subject = PayStreamModel::SYS_TYPE_TEXT[$this->sysType] ?? '退款 - ';

        $thirdRefundNo = (string)RefundStreamModel::query()->where('refundNo', $outRequestNo)->value('thirdRefundNo');

        $result = (new MybankCashierOrderService)->getRefundQueryOrder($payStream->thirdPayNo, $outTradeNo,
            $thirdRefundNo, $payStream->shopId, $subject);

        $formatRes = $this->commonReturn($result);

        $formatRes['data'] = [
            'payNo'             => $outTradeNo,
            'refundNo'          => $outRequestNo,
            'thirdRefundNo'     => $result['data']['refundOrderNo'] ?? 0,
            'totalAmount'       => $result['data']['refundAmount'] ?? 0,
            'refundStatus'      => $this->convertRefundStatus($result['data']['status'] ?? MyBankCashierPayEnum::REFUND_STATUS_APPLY),
            'refundSuccessTime' => $result['data']['refundFinishDate'] ?? 0,
        ];

        return $formatRes;
    }

    public function downloadBill(string $date)
    {
        // TODO: Implement downloadBill() method.
    }

    protected function commonReturn($result): array
    {
        $code = $result['code'] ?? '';
        $msg  = $result['msg'] ?? '';

        if ($code == 200) {
            $status = true;
        } else {
            $status = false;
        }

        return self::returnFormatData($status, $code, $msg, $result);
    }

    /**
     * @param string $subject
     * @param int $amount
     * @param int $expireTime
     * @return array
     */
    public function appPay(string $subject, int $amount, int $expireTime = 0): array
    {
        $tranId = $this->getOutTradeNo();

        $type = MybankOrderRecordModel::TYPE_KFOS_ORDER;

        $model  = new MybankCashierOrderService();

        // 订货收款账户配置id 存在则查配置里的
        $payeeInfo = [];
        if (isset($this->payConfig['companyAccount']) && $this->payConfig['companyAccount'] && isset($this->payConfig['payeeType']) && $this->payConfig['payeeType']) {
            $payeeInfo = [
                'payeeId'   => $this->payConfig['companyAccount'],
                'payeeType' => $this->payConfig['payeeType'],
            ];
        }
        $result = $model->createOrder($this->userId, $amount, $tranId, $type, $subject, $amount, $payeeInfo);

        $formatRes = $this->commonReturn($result);

        Log::info('MybankCashierPay-appPay', [
            'subject'    => $subject,
            'tranId'     => $tranId,
            'amount'     => $amount,
            'expireTime' => $expireTime,
            'result'     => $result,
        ]);

        // pre 生成队列，轮询查询支付结果
        if (config('app.env') == 'pre') {
            PayPolling::dispatch($tranId)->onQueue(PayPolling::QUEUE_NAME)->delay(3);
        }

        $formatRes['data'] = [
            'appPayData' => [
                'body' => $result['data']['orderPayUrl'] ?? '',
            ], // 唤起app支付的数据
            'payNo'      => $tranId,
            'thirdPayNo' => $result['data']['orderNo'] ?? "",
        ];

        return $formatRes;
    }

    /**
     * 获取手续费
     * @param int $payPrice
     * @return array
     */
    public function getFeeAmtByPayPrice(int $payPrice): array
    {
        return [
            round($payPrice * MyBankCashierPayEnum::PAYMENT_RATE), // fee
            number_format(MyBankCashierPayEnum::PAYMENT_RATE, 6, '.', ''), // feeRate
        ];
    }

    /**
     * 转换支付状态
     * @param string $apiTradeStatus
     * @return int
     */
    protected function convertTradeStatus(string $apiTradeStatus): int
    {
        return [
                MyBankCashierPayEnum::TRADE_STATUS_DEALING => BasePayEnum::TRADE_STATUS_WAIT,
                MyBankCashierPayEnum::TRADE_STATUS_OK      => BasePayEnum::TRADE_STATUS_OK,
                MyBankCashierPayEnum::TRADE_STATUS_CLOSED  => BasePayEnum::TRADE_STATUS_CLOSED,
                MyBankCashierPayEnum::TRADE_STATUS_FAIL    => BasePayEnum::TRADE_STATUS_CLOSED,
            ][$apiTradeStatus] ?? BasePayEnum::TRADE_STATUS_WAIT;
    }

    /**
     * 转换退款状态
     * @param string $apiRefundStatus
     * @return int
     */
    protected function convertRefundStatus(string $apiRefundStatus): int
    {
        return [
                MyBankCashierPayEnum::REFUND_STATUS_OK    => BasePayEnum::REFUND_STATUS_OK,
                MyBankCashierPayEnum::REFUND_STATUS_APPLY => BasePayEnum::REFUND_STATUS_WAIT,
                MyBankCashierPayEnum::REFUND_STATUS_FAIL  => BasePayEnum::REFUND_STATUS_ERROR,
            ][$apiRefundStatus] ?? BasePayEnum::REFUND_STATUS_WAIT;
    }
}
